home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Online / Socks5 / src / server / udputil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-10  |  12.6 KB  |  400 lines

  1. /* Copyright (c) 1995-1999 NEC USA, Inc.  All rights reserved.               */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6.  
  7. /*
  8.  * $Id: udputil.c,v 1.46.2.1.2.6 1999/02/03 22:35:54 steve Exp $
  9.  */
  10.  
  11. /* This file has a bunch of utility (caching, socket finding, etc...) funcs  */
  12. /* for use in udp.c...Most of them are pretty simple and obvious.            */
  13. #include "socks5p.h"
  14. #include "threads.h"
  15. #include "daemon.h"
  16. #include "protocol.h"
  17. #include "udputil.h"
  18. #include "validate.h"
  19. #include "info.h"
  20. #include "log.h"
  21. #include "msg.h"
  22. #include "s2s.h"
  23.  
  24. /* Find out which socket we're going to be using to get to host dest...      */
  25. /* Allocate a new entry if we make a new socket to go there...               */
  26. static S5IOHandle MakeOutUdpSocket(UdpInfo *u, S5NetAddr *addr, u_short port) {
  27.     static u_short udpport = 0;
  28.     u_short sudpport, tmpport = ntohs(lsAddr2Port(addr));
  29.     S5IOHandle sd;
  30.     S5NetAddr tmpaddr;
  31.  
  32.     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) == S5InvalidIOHandle) {
  33.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP socket failed for address %s:%d: %m", ADDRANDPORT(addr));
  34.     return S5InvalidIOHandle;
  35.     }
  36.  
  37.     if (ludpport > 0 && udpport == 0) udpport = ludpport;
  38.  
  39.     lsAddrCopy(&tmpaddr, addr, lsAddrSize(addr));
  40.     if (tmpport < ludpport || tmpport > hudpport) {
  41.         if (port == (u_short)0) {
  42.         lsAddrSetPort(&tmpaddr, htons(udpport));
  43.         udpport++;
  44.     } else {
  45.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP client port(%d) is out of range (%d:%d)", (int)tmpport, (int)ludpport, (int)hudpport);
  46.         CLOSESOCKET(sd);
  47.         return S5InvalidIOHandle;
  48.         }
  49.     }
  50.  
  51.     if (bind(sd, &tmpaddr.sa, lsAddrSize(&tmpaddr)) == 0) return sd;
  52.  
  53.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP bind failed for address %s:%d: %m", ADDRANDPORT(&tmpaddr));
  54.  
  55.     if (port == (u_short)0) {
  56.     if (ludpport == 0) {
  57.             lsAddrSetPort(&tmpaddr, 0);
  58.         if (bind(sd, &tmpaddr.sa, lsAddrSize(&tmpaddr)) == 0) return sd;
  59.     } else {
  60.         sudpport = udpport;
  61.         while (udpport < hudpport) {
  62.                 lsAddrSetPort(&tmpaddr, htons(udpport));
  63.         udpport++;
  64.         if (udpport == hudpport) udpport = ludpport;
  65.             if (bind(sd, &tmpaddr.sa, lsAddrSize(&tmpaddr)) == 0) return sd;
  66.         if (udpport == sudpport) break;
  67.         }
  68.     }
  69.     }
  70.  
  71.     CLOSESOCKET(sd);
  72.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP no port is available");
  73.     return S5InvalidIOHandle;
  74. }
  75.  
  76. S5IOHandle MakeOutSocket(UdpInfo *u, S5NetAddr *addr, u_short port) {
  77.     S5IOHandle sd;
  78.     int udpmaxbufsize = 64 * 1024;
  79.     int len = sizeof(int);
  80.     UdpSdRing *sr;
  81.  
  82.     if ((sd = MakeOutUdpSocket(u, addr, port))!=S5InvalidIOHandle) {
  83.         if ((sr = (UdpSdRing *)calloc(1, sizeof(UdpSdRing))) == NULL) {
  84.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP: calloc failed");
  85.             CLOSESOCKET(sd);
  86.             return S5InvalidIOHandle;
  87.         }
  88.  
  89.         sr->sd = sd;
  90.         if (!u->sdring) {
  91.             u->sdring = sr;
  92.             u->sdring->next = u->sdring;
  93.         }
  94.         else {
  95.             sr->next = u->sdring->next;
  96.             u->sdring->next = sr;
  97.         }
  98.  
  99.         setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (const void*)&udpmaxbufsize, len);
  100.     }
  101.  
  102.     return sd;
  103. }
  104.  
  105. /* Find the out socket needed to get to the next hop (either sckAddr or      */
  106. /* dstsin).  If we haven't made a socket for getting there yet, make one and */
  107. /* add it to the route cache.                                                */
  108. S5IOHandle FindOutSocket(UdpInfo *u, S5LinkInfo *pri, const S5NetAddr *nextAddr, const char *nextName) {
  109.     int len = sizeof(S5NetAddr);
  110.     UdpRouteCache *ar;
  111.     S5NetAddr route;
  112.  
  113.     /* XXX IPV6 stuff not finished here                                      */
  114.  
  115.     GetRoute(nextAddr, nextName, "udp", &route);
  116.     lsAddrSetPort(&route, lsAddr2Port(&pri->srcAddr));
  117.  
  118.     for (ar = u->rcache; ar; ar = ar->next) {
  119.         if (!lsAddrIsNull(&ar->raddr) && lsAddr2Port(&ar->raddr) == lsAddr2Port(&pri->srcAddr)) break;
  120.     if (!lsAddrAddrComp(&ar->raddr, &route)) break;
  121.     }
  122.     
  123.     if (!ar) {
  124.     if ((ar = (UdpRouteCache *)calloc(1, sizeof(UdpRouteCache))) == NULL) {
  125.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP: Creating route cache failed");
  126.         return S5InvalidIOHandle;
  127.     }
  128.  
  129.     if ((ar->sd = MakeOutSocket(u, &route, pri->clientPort)) == S5InvalidIOHandle) {
  130.         free(ar);
  131.         return S5InvalidIOHandle;
  132.     }
  133.  
  134.     ar->raddr = route;
  135.         if (getsockname(ar->sd, (ss *)&route.sa, &len) < 0) {
  136.         CLOSESOCKET(ar->sd);
  137.         free(ar);
  138.         return S5InvalidIOHandle;
  139.     }
  140.         lsAddrSetPort(&ar->raddr, lsAddr2Port(&route));
  141.  
  142.     ar->next  = u->rcache;
  143.     u->rcache = ar;
  144.  
  145.         u->maxfd = (u->maxfd > ar->sd)?u->maxfd:ar->sd;
  146.         FD_SET(ar->sd, &u->myfds);
  147.     }
  148.  
  149.     u->curr = ar;
  150.     pri->intAddr = ar->raddr;
  151.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Out interface: %s:%d", ADDRANDPORT(&ar->raddr));
  152.     return ar->sd;
  153. }
  154.  
  155. /* find out if i've talked to this socks server, if not, set up a a cache    */
  156. /* entry for them too...  This does something like...send message to next    */
  157. /* socks5 server; receive a message back, mark that port as the port to talk */
  158. /* to that server.  Then do the client side of authentication with that      */
  159. /* server...                                                                 */
  160. static int AddProxyEntry(UdpInfo *u, S5LinkInfo *pri) {
  161.     UdpSocksCache *sc;
  162.     S5IOHandle outfd;
  163.     S5NetAddr tmp;
  164.  
  165.     if (!(sc = (UdpSocksCache *)calloc(1, sizeof(UdpSocksCache)))) {
  166.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP malloc failed when adding a new proxy");
  167.     return -1;
  168.     }
  169.  
  170.     sc->next   = u->scache;
  171.     sc->tcpsin = pri->sckAddr;
  172.     strcpy(sc->name, pri->sckName);
  173.     InitIdentEntry(sc->idtentry);
  174.     S5BufSetupContext(&sc->cinfo);
  175.     u->scache  = sc;
  176.  
  177.     if ((sc->cinfo.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  178.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP socket failed when contacting proxy: %m");
  179.     goto error;
  180.     }
  181.  
  182.     if ((outfd = FindOutSocket(u, pri, &pri->sckAddr, pri->sckName)) == S5InvalidIOHandle) {
  183.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP couldn't find an output udp socket to use with proxy");
  184.     goto error;
  185.     }
  186.  
  187.     lsAddrCopy(&tmp, &pri->intAddr, lsAddrSize(&pri->intAddr));
  188.  
  189.     if (S5SExchangeProtocol(&u->iio, &sc->cinfo, pri, sc->idtentry, &tmp, &sc->udpsin) < 0) {
  190.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Socks5 Protocol exchange failed");
  191.     goto error;
  192.     }
  193.  
  194.     sc->reserved = pri->nextReserved;
  195.     u->curs = sc;
  196.     return 0;
  197.  
  198.   error:
  199.     u->scache = sc->next;
  200.     S5BufCleanContext(&sc->cinfo);
  201.     free(sc);
  202.     
  203.     return -1;
  204. }
  205.  
  206. /* Find out if this person is a socks server we've talked to or not.         */
  207. /* If we're recv'ing, we're just checking, so we return our result if it is  */
  208. /* still alive...If we're sending, we need to initialize it if it does not   */
  209. /* exist in our cache, so we do exactly that...                              */
  210. int FindProxyEntry(UdpInfo *u, S5LinkInfo *pri, S5NetAddr *sckAddr, int tcp) {
  211.     int found = 0;
  212.     UdpSocksCache *sc, *prev = NULL;
  213.  
  214.     for (sc = u->scache; sc; sc = sc->next) { 
  215.     if (ADDRCOMP((tcp?&sc->tcpsin.sin:&sc->udpsin.sin), &sckAddr->sin)) break;
  216.     prev = sc;
  217.     }
  218.  
  219.     if (sc) {
  220.     found = 1;
  221.     if (S5IOCheck(sc->cinfo.fd) >= 0) {
  222.         if (!tcp) strcpy(pri->sckName, sc->name);
  223.  
  224.         u->oiop          = &sc->cinfo;
  225.         pri->sckAddr     = sc->udpsin;
  226.         pri->nextVersion = SOCKS5_VERSION;
  227.         u->curs = sc;
  228.         
  229.         return 0;
  230.     } else {
  231.         if (prev != NULL) prev->next = sc->next;
  232.         else u->scache = sc->next;
  233.  
  234.         S5BufCleanContext(&sc->cinfo);
  235.         free(sc);
  236.     }
  237.     }
  238.  
  239.     if (!tcp) {
  240.     if (found) return -1;
  241.     memset(&pri->sckAddr, 0, sizeof(S5NetAddr));
  242.     pri->nextVersion = 0;
  243.     u->oiop          = NULL;
  244.     } else {
  245.     if (AddProxyEntry(u, pri) < 0) return -1;
  246.  
  247.     pri->nextVersion = SOCKS5_VERSION;
  248.     pri->sckAddr     = u->scache->udpsin;
  249.     u->oiop          = &u->scache->cinfo;
  250.     }
  251.  
  252.     return 0;
  253. }
  254.  
  255. int CheckIfCached(UdpInfo *u, S5LinkInfo *pri, int checkport) {
  256.     UdpAuthCache *ac;
  257.     UdpRouteCache *ar;
  258.     UdpSocksCache *sc;
  259.     S5NetAddr route;
  260.     u_short port;
  261.  
  262.     u->curs = NULL;
  263.     u->cura = NULL;
  264.     u->curr = NULL;
  265.  
  266.     for (ac = u->acache; ac; ac = ac->next) {
  267.     if (lsAddrAddrComp(&ac->addr, &pri->dstAddr)) continue;
  268.  
  269.     if (checkport) {
  270.         port = lsAddr2Port(&ac->addr);
  271.         if (port != (u_short)0 && port != lsAddr2Port(&pri->dstAddr)) continue;
  272.     }
  273.  
  274.     u->cura = ac;
  275.  
  276.     if (pri->nextVersion) {
  277.             for (sc = u->scache; sc; sc = sc->next) {
  278.             if (!lsAddrComp((checkport)?&sc->tcpsin:&sc->udpsin, &pri->sckAddr)) break;
  279.             }
  280.  
  281.         if ((u->curs = sc) == NULL) {
  282.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "CheckCache: The dst (%s:%d) come from wrong server", ADDRANDPORT(&pri->dstAddr));
  283.         return -1;
  284.         } else {
  285.                 GetRoute(&sc->udpsin, sc->name, "udp", &route);
  286.                 for (ar = u->rcache; ar; ar = ar->next) {
  287.                     if (!lsAddrIsNull(&ar->raddr) && lsAddr2Port(&ar->raddr) == lsAddr2Port(&pri->srcAddr)) break;
  288.                 if (!lsAddrAddrComp(&ar->raddr, &route)) break;
  289.                 }
  290.  
  291.             if ((u->curr = ar) == NULL) {
  292.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "CheckCache: The dst (%s:%d) come from wrong route", ADDRANDPORT(&sc->udpsin));
  293.             return -1;
  294.             } else return 0;
  295.         }
  296.     } else {
  297.             GetRoute(&pri->dstAddr, pri->dstName, "udp", &route);
  298.             for (ar = u->rcache; ar; ar = ar->next) {
  299.                 if (!lsAddrIsNull(&ar->raddr) && lsAddr2Port(&ar->raddr) == lsAddr2Port(&pri->srcAddr)) break;
  300.  
  301.             if (!lsAddrAddrComp(&ar->raddr, &route)) break;
  302.             }
  303.  
  304.         if ((u->curr = ar) == NULL) {
  305.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "CheckCache: The dst (%s:%d) come from wrong route", ADDRANDPORT(&pri->dstAddr));
  306.         return -1;
  307.         } else return 0;
  308.     }
  309.     }
  310.  
  311.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "CheckCache: The dst (%s:%d) is not cached", ADDRANDPORT(&pri->dstAddr));
  312.     return -1;
  313. }
  314.  
  315. /* Is the current set of global variables allowed to proxy or not...?  If it */
  316. /* is, set the global variables we use (next_version, out) with the cached   */
  317. /* info...                                                                   */
  318. int CheckIfAllowed(UdpInfo *u, S5LinkInfo *pri) {
  319.     UdpAuthCache *ac;
  320.  
  321.     /* haven't sent from the client to this host yet I guess we had better     */
  322.     /* make sure we're allowed to...then find out where we're sending it,      */
  323.     /* and resolve the names/reset the version if we need to.                  */
  324.     if (Authorize(pri, 0) != AUTH_OK) {
  325.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP authorization failed");
  326.     return -1;
  327.     }
  328.  
  329.     /* since we were allowed to talk, we should cache this entry...            */
  330.     if (!(ac = (UdpAuthCache *)calloc(1, sizeof(UdpAuthCache)))) {
  331.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP calloc failed when allocating auth cache entry");
  332.     return -1;
  333.     } 
  334.  
  335.     lsAddrCopy(&ac->addr, &pri->dstAddr, sizeof(S5NetAddr));
  336.     ac->next  = u->acache;
  337.     u->acache = ac;
  338.     u->cura = ac;
  339.  
  340.     return 0;
  341. }
  342.  
  343.  
  344. int WasResolved(UdpInfo *u, S5NetAddr *dst, char *name) {
  345. #ifdef SENDBACK_NAMES
  346.     UdpHostCache *h;
  347.     char *res;
  348.  
  349.     if (dst->sa.sa_family != AF_INET) {
  350.     return 0;
  351.     }
  352.  
  353.     /* Find out if we looked up a name and found this address...             */
  354.     for (h = u->hcache; h; h=h->next) {
  355.     if (h->addr.s_addr == dst->sin_addr.s_addr) break;
  356.     }
  357.  
  358.     if (h && strcmp(h->name, name)) {
  359.     strncpy(name, h->name, MIN(strlen(h->name)+1, S5_HOSTNAME_LEN));
  360.     if (strlen(h->h_name)+1 > S5_HOSTNAME_SIZE) name[S5_HOSTNAME_SIZE-1] = '\0';
  361.     }
  362.  
  363.     return h?1:0;
  364. #else
  365.     return 0;
  366. #endif
  367. }
  368.  
  369. void MarkResolved(UdpInfo *u, S5NetAddr *dst, char *name) {
  370. #ifdef SENDBACK_NAMES
  371.     UdpHostCache *h;
  372.  
  373.     /* If this host wasn't resolve (we're giving the name to the next        */
  374.     /* server), don't cache it, we won't be using it...                      */
  375.     if (dst->sa.sa_family != AF_INET) {
  376.     return;
  377.     }
  378.  
  379.     /* Find out if there was an entry already...                             */
  380.     for (h = u->hcache; h; h=h->next) {
  381.     if (strcmp(h->name, name)) break;
  382.     }
  383.  
  384.     if (h) {
  385.     return;
  386.     }
  387.  
  388.     if (!(h = (UdpHostCache *)malloc(sizeof(UdpHostCache)))) {
  389.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Malloc failed when allocating resolved host entry");
  390.     return;
  391.     }
  392.  
  393.     strcpy(h->name, name);
  394.     h->addr = dst->sin.sin_addr;
  395.     h->next = u->hcache;
  396.     u->hcache = h;
  397. #endif
  398. }
  399.  
  400.